Библиотеки для глубокого обучения: TensorFlow и Keras

TensorFlow — это основанная на Python, бесплатная, open-source платформа машинного обучения, разработанная в основном Google.
Keras — это API глубокого обучения на Python, которое облегчает использование TensorFlow. Изначально Keras был построен вокруг библиотеки Theano, затем поддерживал несколько бэкендов (Theano, CNTK, MXNet, Tensorflow), сейчас остался только один бэкенд Tensorflow.

Использовать библиотеки глубокого обучения желательно с GPU для ускорения работы. Для этого есть три возможности:
1. Использовать NVIDIA GPU.
2. Использовать Google Cloud Platform или AWS EC2.
3. Использовать бесплатный Colaboratory — сервис «блокнотов» Jupyter от Google.
Colaboratory — самый простой способ для начала, поскольку он не требует покупки оборудования или установки программ. Однако, бесплатно Colaboratory подходит только для небольших тестов.
__________________________
Fashion_MNIST.ipynb
__________________________

{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Fashion MNIST.ipynb",
      "provenance": [],
      "collapsed_sections": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tpqAGEKFtpW5",
        "colab_type": "text"
      },
      "source": [
        "#Общая информация\n",
        "\n",
        "Традиционно набор данных MNIST применяется для старта в освоении машинного обучения и компьютерного зрения.\n",
        "\n",
        "\n",
        "В качестве альтернативного набора, также, достаточно часто применяется  набор данных **Fashion MNIST**. Подобно MNIST изображения одежды в Fashion MNIST представляют собой двумерные массивы 28х28, где значения в каждой ячейке могут быть в интервале [0, 255]. Метки — массив целых чисел, где каждое значение в интервале [0, 9]. Каждая метка соответствует одному из классов: футболка; шорты; свитер; платье; плащ; сандали; рубашка; кроссовок; сумка; ботинок.\n",
        "\n",
        "\n",
        "Оба набора данных достаточно малы, поэтому часто используются для проверки корректности работы алгоритма, тестирования и отладки кода. \n",
        "\n",
        "\n",
        "Основная цель лабораторной работы – знакомство с набором данных Fashion MNIST. Лабораторная работа основана на материалах, представленных на официальном сайте https://www.tensorflow.org/. Полная версия материалу доступна по ссылке: https://www.tensorflow.org/tutorials/keras/classification?hl=ru\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qHYt8zXLnd1Q",
        "colab_type": "text"
      },
      "source": [
        "# Простая классификация изображений одежды\n",
        "\n",
        "\n",
        "Руководство использует [tf.keras](https://www.tensorflow.org/guide/keras), высокоуровневый API для построения и обучения моделей в TensorFlow.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "pEu0AlO1kkbw",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "# TensorFlow и tf.keras\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "# Вспомогательные библиотеки\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "print(tf.__version__)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0xRvstxWoS5o",
        "colab_type": "text"
      },
      "source": [
        "Загрузка датасета [Fashion MNIST](https://github.com/zalandoresearch/fashion-mnist). Датасет содержит 70,000 монохромных изображений в 10 категориях. На каждом изображении содержится по одному предмету одежды в низком разрешении (28 на 28 пикселей):\n",
        "\n",
        "| Метка (Label)  | Класс  | Class |\n",
        "|:------------- |:---------------| :-------------|\n",
        "| 0 |Футболки / сверху |  T-shirt/top    |\n",
        "| 1 |  Брюки       |  Trouser      |\n",
        "| 2 |    Свитер     |    Pullover    |\n",
        "| 3 |   Платье      |   Dress     |\n",
        "| 4 |    Пальто     |   Coat     |\n",
        "| 5 |    Сандаль     |  Sandal      |\n",
        "| 6 |   Рубашка      |   Shirt     |\n",
        "| 7 |    Кроссовок     |    Sneaker    |\n",
        "| 8 |     Сумка    |    Bag    |\n",
        "| 9 |       Ботильоны |    Ankle boot    |\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XEQNhUSvkrrj",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "fashion_mnist = keras.datasets.fashion_mnist\n",
        "\n",
        "(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Fe2eeAeku7ub",
        "colab_type": "text"
      },
      "source": [
        "Загрузка датасета возвращает четыре массива NumPy:\n",
        "\n",
        "Массивы train_images и train_labels являются тренировочным сетом — данными, на которых модель будет обучаться.\n",
        "Модель тестируется на проверочном сете, а именно массивах test_images и test_labels.\n",
        "Изображения являются 28х28 массивами NumPy, где значение пикселей варьируется от 0 до 255. Метки - это массив целых чисел от 0 до 9. Они соответствуют классам одежды изображенной на картинках."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v_Egshumncv1",
        "colab_type": "text"
      },
      "source": [
        "Каждому изображению соответствует единственная метка. Так как названия классов не включены в датасет, сохраним их тут для дальнейшего использования при построении изображений:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "kafZZhHYvVLA",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UtnV5ch9vsF2",
        "colab_type": "text"
      },
      "source": [
        "# Познакомимся с данными\n",
        "\n",
        "Используя метод **shape** мы видим, что в тренировочном датасете 60,000 изображений, каждое размером 28 x 28 пикселей:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "QpD7HtyNvivY",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "train_images.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7XDk5R11wKuY",
        "colab_type": "text"
      },
      "source": [
        "Соответственно, в тренировочном сете 60,000 меток:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Dq97foEqwGcs",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "len(train_labels)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Q1qs2tLZwTN8",
        "colab_type": "text"
      },
      "source": [
        "Каждая метка это целое число от 0 до 9:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "qP9QbAARwNY6",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "train_labels"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uF57XbkEwcec",
        "colab_type": "text"
      },
      "source": [
        "Проверочный сет содержит 10,000 изображений, каждое - также 28 на 28 пикселей:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_xITtNrhwR-8",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "test_images.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U7REQU9Pwh_k",
        "colab_type": "text"
      },
      "source": [
        "И в проверочном сете - ровно 10,000 меток:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xCg1GPX3wfXb",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "len(test_labels)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2QM2_lzxwojv",
        "colab_type": "text"
      },
      "source": [
        "# Предобработка данных\n",
        "\n",
        "Данные должны быть предобработаны перед обучением нейросети. Если вы посмотрите на первое изображение в тренировочном сете вы увидите, что значения пикселей находятся в диапазоне от 0 до 255:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "WeNI24mjwkil",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "plt.figure()\n",
        "plt.imshow(train_images[1])\n",
        "plt.colorbar()\n",
        "plt.grid(False)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JPJ9fYRQxExS",
        "colab_type": "text"
      },
      "source": [
        "Мы масштабируем эти значения к диапазону от 0 до 1 перед тем как применять данные для обучения нейросети. Для этого нужно разделить значения на 255. \n",
        "\n",
        "\n",
        "Важно, чтобы тренировочный сет и проверочный сет были предобработаны одинаково:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "plmLJ1MDw8F4",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "train_images = train_images / 255.0\n",
        "\n",
        "test_images = test_images / 255.0"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EoPo7fdRxYAO",
        "colab_type": "text"
      },
      "source": [
        "Чтобы убедиться, что данные в правильном формате и мы готовы построить и обучить нейросеть, выведем на экран первые 25 изображений из тренировочного сета и отобразим под ними наименования их классов:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "2ytQ2ymxxUro",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "plt.figure(figsize=(10,10))\n",
        "for i in range(25):\n",
        "    plt.subplot(5,5,i+1)\n",
        "    plt.xticks([])\n",
        "    plt.yticks([])\n",
        "    plt.grid(False)\n",
        "    plt.imshow(train_images[i], cmap=plt.cm.binary)\n",
        "    plt.xlabel(class_names[train_labels[i]])\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xyiEjVhtxnqX",
        "colab_type": "text"
      },
      "source": [
        "# Построение модели нейронной сети\n",
        "\n",
        "### Настройте слои\n",
        "\n",
        "Базовым строительным блоком нейронной сети является слой. \n",
        "\n",
        "\n",
        "Слои извлекают образы из данных, которые в них подаются. \n",
        "\n",
        "Большая часть глубокого обучения состоит из соединения в последовательность простых слоев. Большинство слоев, таких как tf.keras.layers.Dense, имеют параметры, которые настраиваются во время обучения."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "b3m_7uNsxftc",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "model = keras.Sequential([\n",
        "    keras.layers.Flatten(input_shape=(28, 28)),\n",
        "    keras.layers.Dense(128, activation='relu'),\n",
        "    keras.layers.Dense(10, activation='softmax')\n",
        "])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "waZ1IIHX1avz",
        "colab_type": "text"
      },
      "source": [
        "Первый слой этой сети - tf.keras.layers.Flatten, преобразует формат изображения из двумерного массива (28 на 28 пикселей) в одномерный (размерностью 28 * 28 = 784 пикселя). Слой извлекает строки пикселей из изображения и выстраивает их в один ряд. Этот слой не имеет параметров для обучения; он только переформатирует данные.\n",
        "\n",
        "После разложения пикселей, нейросеть содержит два слоя tf.keras.layers.Dense. Это полносвязные нейронные слои. Первый Dense слой состоит из 128 узлов (или нейронов). Второй (и последний) 10-узловой softmax слой возвращает массив из 10 вероятностных оценок дающих в сумме 1. Каждый узел содержит оценку указывающую вероятность принадлежности изображения к одному из 10 классов.\n",
        "\n",
        "# Скомпилируйте модель\n",
        "Прежде чем модель будет готова для обучения, нам нужно указать еще несколько параметров. Они добавляются на шаге compile модели:\n",
        "\n",
        "*   Функция потерь (Loss function) — измеряет точность модели во время обучения. Мы хотим минимизировать эту функцию чтоб \"направить\" модель в верном направлении.\n",
        "*   Оптимизатор (Optimizer) — показывает каким образом обновляется модель на основе входных данных и функции потерь.\n",
        "* Метрики (Metrics) — используются для мониторинга тренировки и тестирования модели. Наш пример использует метрику accuracy равную доле правильно классифицированных изображений.\n",
        "\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "49iITZhk1VZo",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "model.compile(optimizer='adam',\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y2UdbC_Z2J6W",
        "colab_type": "text"
      },
      "source": [
        "# Обучите модель\n",
        "\n",
        "Обучение модели нейронной сети требует выполнения следующих шагов::\n",
        "\n",
        "1. Подайте тренировочный данные в модель. В этом примере тренировочные данные это массивы train_images и train_labels.\n",
        "2. Модель учится ассоциировать изображения с правильными классами.\n",
        "3. Мы просим модель сделать прогнозы для проверочных данных, в этом примере массив test_images. Мы проверяем, соответствуют ли предсказанные классы меткам из массива test_labels.\n",
        "Для начала обучения, вызовите метод model.fit, который называется так, поскольку \"тренирует (fits)\" модель на тренировочных данных:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "17T4AzJz16ak",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "model.fit(train_images, train_labels, epochs=10)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SL6kXNuW2dgZ",
        "colab_type": "text"
      },
      "source": [
        "В процессе обучения модели отображаются метрики потери (loss) и точности (accuracy). Эта модель достигает на тренировочных данных точности равной приблизительно 0.88 (88%).\n",
        "\n",
        "\n",
        "# Оценка точности\n",
        "Далее, сравните какую точность модель покажет на проверчном датасете:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XC26x5F22Y9a",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "\n",
        "print('\\nТочность на проверочных данных:', test_acc)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ICgknJCk2t_3",
        "colab_type": "text"
      },
      "source": [
        "Полученная на проверочном сете точность оказалась немного ниже, чем на тренировочном. Этот разрыв между точностью на тренировке и тесте является примером переобучения (overfitting) . Переобучение возникает, когда модель машинного обучения показывает на новых данных худший результат, чем на тех, на которых она обучалась.\n",
        "\n",
        "## Сделайте предсказания\n",
        "Теперь, когда модель обучена, мы можем использовать ее чтобы сделать предсказания по поводу нескольких изображений:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "udReKlXJ2qOI",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "predictions = model.predict(test_images)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DgNBB2ZG2zqR",
        "colab_type": "text"
      },
      "source": [
        "Здесь полученная модель предсказала класс одежды для каждого изображения в проверочном датасете. Давайте посмотрим на первое предсказание:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "UmNv_28I2ySO",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "predictions[0]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LF8NX1r-27GE",
        "colab_type": "text"
      },
      "source": [
        "Прогноз представляет из себя массив из 10 чисел. Они описывают \"уверенность\" (confidence) модели в том, насколько изображение соответствует каждому из 10 разных видов одежды. Мы можем посмотреть какой метке соответствует максимальное значение:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "EBGudGjE24AW",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "np.argmax(predictions[0])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d569g0d-3Acy",
        "colab_type": "text"
      },
      "source": [
        "Модель полагает, что на первой картинке изображен ботинок (ankle boot), или class_names[9]. Проверка показывает, что классификация верна:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "3R099DPv29SH",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "test_labels[0]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2IzBRgVL3GMw",
        "colab_type": "text"
      },
      "source": [
        "Мы можем построить график, чтобы взглянуть на полный набор из 10 предсказаний классов."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "kT08929W3DBl",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def plot_image(i, predictions_array, true_label, img):\n",
        "  predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]\n",
        "  plt.grid(False)\n",
        "  plt.xticks([])\n",
        "  plt.yticks([])\n",
        "\n",
        "  plt.imshow(img, cmap=plt.cm.binary)\n",
        "\n",
        "  predicted_label = np.argmax(predictions_array)\n",
        "  if predicted_label == true_label:\n",
        "    color = 'blue'\n",
        "  else:\n",
        "    color = 'red'\n",
        "\n",
        "  plt.xlabel(\"{} {:2.0f}% ({})\".format(class_names[predicted_label],\n",
        "                                100*np.max(predictions_array),\n",
        "                                class_names[true_label]),\n",
        "                                color=color)\n",
        "\n",
        "def plot_value_array(i, predictions_array, true_label):\n",
        "  predictions_array, true_label = predictions_array[i], true_label[i]\n",
        "  plt.grid(False)\n",
        "  plt.xticks([])\n",
        "  plt.yticks([])\n",
        "  thisplot = plt.bar(range(10), predictions_array, color=\"#777777\")\n",
        "  plt.ylim([0, 1])\n",
        "  predicted_label = np.argmax(predictions_array)\n",
        "\n",
        "  thisplot[predicted_label].set_color('red')\n",
        "  thisplot[true_label].set_color('blue')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "65j6lzAv3NtN",
        "colab_type": "text"
      },
      "source": [
        "Давайте посмотрим на нулевое изображение, предсказание и массив предсказаний."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "qJt3gJZv3LLc",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "i = 0\n",
        "plt.figure(figsize=(6,3))\n",
        "plt.subplot(1,2,1)\n",
        "plot_image(i, predictions, test_labels, test_images)\n",
        "plt.subplot(1,2,2)\n",
        "plot_value_array(i, predictions,  test_labels)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "SQmUKLBx3QXl",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "i = 12\n",
        "plt.figure(figsize=(6,3))\n",
        "plt.subplot(1,2,1)\n",
        "plot_image(i, predictions, test_labels, test_images)\n",
        "plt.subplot(1,2,2)\n",
        "plot_value_array(i, predictions,  test_labels)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fWYzzIIY3Wo5",
        "colab_type": "text"
      },
      "source": [
        "Давайте посмотрим несколько изображений с их прогнозами. Цвет верных предсказаний синий, а неверных - красный. Число это процент уверенности (от 100) для предсказанной метки. Отметим, что модель может ошибаться даже если она очень уверена."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4Tn5SviJ3Txo",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Отображаем первые X тестовых изображений, их предсказанную и настоящую метки.\n",
        "# Корректные предсказания окрашиваем в синий цвет, ошибочные в красный.\n",
        "num_rows = 5\n",
        "num_cols = 3\n",
        "num_images = num_rows*num_cols\n",
        "plt.figure(figsize=(2*2*num_cols, 2*num_rows))\n",
        "for i in range(num_images):\n",
        "  plt.subplot(num_rows, 2*num_cols, 2*i+1)\n",
        "  plot_image(i, predictions, test_labels, test_images)\n",
        "  plt.subplot(num_rows, 2*num_cols, 2*i+2)\n",
        "  plot_value_array(i, predictions, test_labels)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0aXl42vS3dup",
        "colab_type": "text"
      },
      "source": [
        "Наконец, используем обученную модель для предсказания класса на одном изображении."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "uAyGMLGs3ZdB",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Берем одну картинку из проверочного сета.\n",
        "img = test_images[0]\n",
        "\n",
        "print(img.shape)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "stWH7B4x3jLC",
        "colab_type": "text"
      },
      "source": [
        "Модели tf.keras оптимизированы для предсказаний на пакетах (batch) данных, или на множестве примеров сразу. Таким образом, даже если мы используем всего 1 картинку, нам все равно необходимо добавить ее в список:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-IEefWRD3gUn",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Добавляем изображение в пакет данных, состоящий только из одного элемента.\n",
        "img = (np.expand_dims(img,0))\n",
        "\n",
        "print(img.shape)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9x75eIZG3oS4",
        "colab_type": "text"
      },
      "source": [
        "Сейчас предскажем правильную метку для изображения:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "cCphJFRB3lss",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "predictions_single = model.predict(img)\n",
        "\n",
        "print(predictions_single)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "M-GLLm353qnQ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "plot_value_array(0, predictions_single, test_labels)\n",
        "_ = plt.xticks(range(10), class_names, rotation=45)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BcfKi9Ru3tCi",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "np.argmax(predictions_single[0])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mhxfgWDG30Wp",
        "colab_type": "text"
      },
      "source": [
        "И, как и ранее, модель предсказывает класс 9."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3_3ee5plx7_S",
        "colab_type": "text"
      },
      "source": [
        "# Задание\n",
        "Сфотографируйте элемент своей одежды (например, ботинок), добавьте код для предобработки изображений, попробуйте определить класс предмета одежды с помощью обученной нейронной сети."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BtGYPis1yfzB",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}